home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
NeXT Education Software Sampler 1992 Fall
/
NeXT Education Software Sampler 1992 Fall.iso
/
Programming
/
Source
/
Weather
/
Weather.app
/
state.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-07-01
|
8KB
|
351 lines
/*
* State machine and menu abstraction.
* The idea is to keep as much of the hookup dialog
* as possible in a text file, so that menus and hookup protocols
* are easy to change here or in other apps.
* It has grown a few warts.
*
* M. J. Hawley
* mike@media-lab.mit.edu
* Copyright (c) November 1991, MIT Media Laboratory.
*/
#define MENU 1
typedef enum { Plain, Pattern, Status, Goto, FlushS, Pause, CmdS } SType;
typedef struct String {
char *s;
struct String *next;
} String;
typedef struct MenuItem {
char *send, *get, *label;
struct MenuItem *next;
} MenuItem;
typedef struct {
int type;
char *name;
char *first, *last, *label;
String *l;
MenuItem *m;
} State;
#include "util.h"
SType lastType = Plain;
char *getStr(s,t) char *s, *t; {
char end = ' ';
*t = '\0';
s = skipsp(s);
lastType = Plain;
switch (*s){
Case '/': lastType = Pattern;
Case '+': lastType = Status; s++;
Case '!': lastType = CmdS; s++;
Case ',': lastType = FlushS; s++;
Case '=': lastType = Goto; s = skipsp(s+2);
}
if (*s=='/' || *s == '"') end = *s++;
while (*s && !(*s == end || (end==' ' && *s == '\t'))){
*t = *s++;
if (*t == '\\') switch (*s){
Case 'n': *t = '\n'; s++;
Case 't': *t = '\t'; s++;
Case 'b': *t = '\b'; s++;
Default : *t = *s; s++;
}
t++;
}
*t = '\0';
if (*s && *s != ' ' && *s != '\t') ++s;
if (*s) s = skipsp(s);
return s;
}
State *
newMenu(s) char *s; {
State *S = Alloc(State);
char n[1024], first[1024], last[1024], label[1024];
s = skipsp(skipsp(s)+4);
sscanf(s,"%[^:]",n);
s = skipsp(index(s,':')+1);
s = getStr(s,first);
s = getStr(s,last);
s = getStr(s,label);
S->name = save(n);
S->label = save(label);
S->first = save(first);
S->last = save(last);
S->type = MENU;
return S;
}
State *
newState(s) char *s; {
State *S = Alloc(State);
S->name = save(s);
return S;
}
String *
addStr(s,t) String *s; char *t; {
String *start = s, *n = Alloc(String);
char *p;
p = n->s = save(t);
if (*p=='/' && (p = index(p+1,'/'))){
while (p[-1]=='\\') p = index(p+1,'/');
if (p) *p = '\0';
}
if (!s) return n;
while (s->next) s = s->next;
s->next = n;
return start;
}
stripq(s) char *s; {
if (*s == '\"'){
strcpy(s,s+1);
if (s = rindex(s,'\"')) *s = '\0';
}
}
void
addMenu(S,s) State *S; char *s; {
char send[1024], get[1024], label[1024];
MenuItem *m = Alloc(MenuItem), *t;
s = getStr(s,send); m->send = save(send);
s = getStr(s,get); m->get = save(get);
skipsp(s); strcpy(label,s); stripnl(label); stripq(label); m->label = save(label);
for (t=S->m; t && t->next; t = t->next) ;
if (t) t->next = m; else S->m = m;
}
void
addString(S,s) State *S; char *s; {
stripnl(s=skipsp(s));
S->l = addStr(S->l,s);
}
#define MaxS 256
static State *ST[MaxS];
static int NS = 0;
void
readState(f) FILE *f; {
char s[1024], n[1024];
State *S = (State *)0;
while (fgets(s,sizeof s,f)){
stripcomment(s);
if (blank(s)) continue;
if (strncmp(s,"Menu",4)==0){
S = newMenu(s);
ST[NS++] = S;
} else
if (match(s,"[a-zA-Z]*:")){
sscanf(s,"%[^:]",n);
S = newState(n);
ST[NS++] = S;
} else
if (S){
if (S->type == MENU) addMenu(S,s); else
addString(S,s);
}
}
}
State*
state(s) char *s; {
int i;
s = skipsp(s);
for (i=0;i<NS;i++)
if (strcmp(s,ST[i]->name)==0) return ST[i];
return (State *)0;
}
char *str(s) char *s; { return s? s : ""; }
void
printState(s) State *s; {
if (!s) return printf("huh?\n");
printf("%s: %s %s %s\n",s->name,str(s->first),str(s->last),str(s->label));
}
void
ReadState(s) char *s; {
FILE *f;
if (!NS){
f = fopen(s,"r");
if (f) readState(f), fclose(f);
}
setState("Attach");
setMenu("Main");
}
State *curState = (State *)0;
void
setState(s) char *s; {
curState = state(s);
if (strcmp(s,"Detach")==0) logout();
if (strcmp(s,"Ready")==0) fetchReports();
}
void
execute(s) char *s; {
char t[1024];
if (s[0]=='/') s += strlen(s)+1;
while ((s=getStr(s,t)) && *t) switch (lastType){
Case CmdS: Command(t);
Case Status : message(t);
Case Plain : if (!state(t)) Put("%s",t);
Case FlushS : Flush(t);
Case Goto : setState(t);
}
}
void
execState(s,t) State *s; char *t; {
String *l;
if (!s) s = curState;
if (!s || !s->l) return;
for (l=s->l; l; l=l->next){
if (l->s[0]!='/') execute(l->s);
else
if (l->s[0]=='/' && *t && match(t,l->s+1)) execute(l->s);
}
}
void
runState(s) char *s; {
execState(curState,s);
}
int numItem(s) char *s; {
int i = 0;
State *S = state(s);
MenuItem *m;
if (!S) return 0;
for (m=S->m; m; m=m->next) i++;
return i;
}
State *curMenu;
setMenu(s) char *s; { curMenu = state(s); }
MenuItem *
curMenuItem(n) int n; {
MenuItem *m;
if (!curMenu) return (MenuItem *)0;
for (m=curMenu->m; m && n-->0; m = m->next) ;
return m;
}
valid(m) MenuItem *m; {
MenuItem *t;
if (!curMenu) return 0;
for (t=curMenu->m; t; t=t->next)
if (t==m) return 1;
return 0;
}
char *getLabel(m) MenuItem *m; { return valid(m)? m->label : ""; }
char *getSend(m) MenuItem *m; { return valid(m)? m->send : ""; }
char *getGet(m) MenuItem *m; { return valid(m)? m->get : ""; }
char *curMenuFirst() { return curMenu? curMenu->first : "**nada**"; }
char *curMenuLast() { return curMenu? curMenu->last : "**nada**"; }
char *
getReport(buf) char *buf; {
char *p = buf+1;
int starting = 1;
strcpy(buf,"\n");
while (pgets(p,1024) && !strindex(p,curMenuFirst())){
if (Verbose) printf("+%s",p);
if (starting && strlen(p)<=5)
;
else
if (strindex(p,"Enter 3-letter") || strindex(p,"Enter 2-letter")
|| strindex(p,"Selection:"))
;
else
if (strindex(p,"ress return") || strindex(p,"ress Return"))
Put("\n");
else
starting = 0, p += strlen(p);
}
*p = '\0';
if (curMenu) Flush(curMenuLast());
return buf;
}
MenuItem *
menuFor(label,name) char *label, *name; {
int i;
MenuItem *m;
*name = '\0';
for (i=0;i<NS;i++){
if (ST[i]->type == MENU){
for (m=ST[i]->m;m;m=m->next)
if (strcmp(label,m->label)==0){
strcpy(name,ST[i]->name);
return m;
}
}
}
return (MenuItem *)0;
}
#define hackflush() sleep(1); while (pgets(hack,1024) && !strindex(hack,curMenuLast())) if (Verbose) printf("+%s",hack)
void
fetchReport(label,buf) char *label, *buf; {
char menu[256];
char hack[1024];
MenuItem *m = menuFor(label,menu);
*buf = '\0';
if (!m) return;
{
State *s = state("Main");
MenuItem *t = s->m;
for (;t && strcmp(t->get,menu);t=t->next) ;
if (t)
Put("%s",t->send);
}
setMenu(menu); hackflush();
Put("%s",m->send);
if (strcmp(menu,"Main")==0) pgets(hack,1024);
getReport(buf);
if (strcmp(curMenu->name,"Main")){
Put("m\n"), setMenu("Main");
hackflush();
} else
hackflush();
}
/*
print(){
int i;
for (i=0;i<NS;i++) printState(ST[i]);
}
main(){
char s[1024];
ReadState("states");
print();
setState("Attach");
*s = '\0';
do { runState(s); } while (gets(s));
}
*/